using System;
using System.Reflection;
using System.Web;
using Castle.ActiveRecord;
using Cognitum.Dominio.Aplicacion.Seguridad;
using log4net;
using Karma.Framework.Core;
using Karma.Framework.Core.IoC;
using Karma.Framework.Core.Metadata.Mapping;
using Ctx = Karma.Framework.Core.Security.Context;

namespace Cognitum.Presentacion
{
    public class Global : HttpApplication
    {
        private static ILog LOG = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);

        public Global()
        {
            BeginRequest += onBeginRequest;
            EndRequest += onEndRequest;
            PostAuthenticateRequest += onPostAuthenticateRequest;
        }
        
        protected void Application_Start(object sender, EventArgs e)
        {
            //HibernatingRhinos.NHibernate.Profiler.Appender.NHibernateProfiler.Initialize();
            KarmaStarter.InitializeFramework();

            var context = HttpContext.Current;
            if (context.Application[typeof(Application).Name] == null)
            {
                var aplicacionService = IoCFactory.Resolve<IApplicationService>();
                var meta = aplicacionService.ObtenerMetadatos();
                context.Application[typeof(Application).Name] = meta;
            }
        }

        protected void Session_Start(object sender, EventArgs e)
        {

        }

        protected void onBeginRequest(object sender, EventArgs e)
        {
            if (LOG.IsDebugEnabled)
            {
                LOG.Debug ("Opening session scope...");
            }
            if (HttpContext.Current.Items.Contains("ar.sessionscope"))
            {
                if (LOG.IsDebugEnabled)
                {
                    LOG.Debug("ar.sessionscope already exists, assign to the existing entry...");
                }
                HttpContext.Current.Items["ar.sessionscope"] = new SessionScope();
            }
            else
            {
                if (LOG.IsDebugEnabled)
                {
                    LOG.Debug("ar.sessionscope does not exists, create new entry...");
                }
                HttpContext.Current.Items.Add("ar.sessionscope", new SessionScope());
            }
            var context = HttpContext.Current;
            Ctx.Set(typeof(Application).Name, context.Application[typeof(Application).Name]);
            if (LOG.IsDebugEnabled)
            {
                LOG.Debug("Opening session scope set in the context.");
            }

            var repo = IoCFactory.Resolve<IUsuarioRepository>();
            Ctx.PrincipalRepository = repo.ObtenerPorUsername;
        }

        public void onEndRequest(object sender, EventArgs e)
        {
            if (LOG.IsDebugEnabled)
            {
                LOG.Debug("Disposing session scope...");
            }
            try
            {
                var scope = HttpContext.Current.Items["ar.sessionscope"] as SessionScope;
                if (LOG.IsDebugEnabled)
                {
                    LOG.Debug(string.Format("The session [{0}].", scope));
                }
                HttpContext.Current.Items.Remove("ar.sessionscope");
                if (scope != null)
                {
                    try
                    {
                        if (LOG.IsDebugEnabled)
                        {
                            LOG.Debug("Disposing the scope.");
                        }
                        scope.Dispose();
                        if (LOG.IsDebugEnabled)
                        {
                            LOG.Debug("The scope has been disposed.");
                        }
                    }
                    catch (ObjectDisposedException)
                    {
                    }
                }
                else
                {
                    if (LOG.IsDebugEnabled)
                    {
                        LOG.Debug("The scope is null.");
                    }
                }
            }
            catch (Exception ex)
            {
                if (LOG.IsDebugEnabled)
                {
                    LOG.Debug("An exception has been thrown:", ex);
                }
                HttpContext.Current.Trace.Warn("Error", "EndRequest: " + ex.Message, ex);
            }
        }

        protected void Application_AuthenticateRequest(object sender, EventArgs e)
        {
        }

        protected void onPostAuthenticateRequest(object sender, EventArgs e)
        {
            var principal = HttpContext.Current.User;
            if (principal != null)
            {
                if (LOG.IsDebugEnabled)
                {
                    LOG.Debug(string.Format("Current principal: {0}", principal));
                    LOG.Debug(string.Format("Identity: {0}", principal.Identity));
                    LOG.Debug(string.Format("Username: {0}", principal.Identity.Name));
                }
                if (!String.IsNullOrEmpty(principal.Identity.Name))
                {
                    var datos = principal.Identity.Name.Split(new[] { '\\' },
                        StringSplitOptions.RemoveEmptyEntries);
                    Ctx.Set("Usuario", datos[1]);
                    Ctx.Set("Dominio", datos[0]);
                }
            }
        }

        protected void Application_Error(object sender, EventArgs e)
        {
            var err = Server.GetLastError();
            LOG.Fatal("An uncaught exception occurred.");
            LOG.Fatal(string.Format(" Message [{0}]", err.Message), err);
        }

        protected void Session_End(object sender, EventArgs e)
        {
        }

        protected void Application_End(object sender, EventArgs e)
        {
        }
    }
}